/*
    Copyright  Louis CHEREL cherel.louis@gmail.com  
    This file is part of Agenda de l'Efrei.

    Agenda de l'Efrei is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Agenda de l'Efrei is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Agenda de l'Efrei.  If not, see <http://www.gnu.org/licenses/>.
 */

package fr.efrei.AgendaEfrei;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.*;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.net.ssl.HttpsURLConnection;

public class NotesUpdater extends AsyncTask<Void,Void,Void> {

    protected Context parent;
    protected TableLayout tl;
    protected TextView tv;
    protected TableRow tr;
    protected String ret="";
    protected boolean newUser=false;

    NotesUpdater(Context c){
        parent = c;
    }
    
    @Override
    protected Void doInBackground(Void... v) {
        //tl=tl_[0];
        if(!ViewNotes.getIsNotesUpdaterLaunched())
        {
            ViewNotes.setIsNotesUpdaterLaunched(true);
            CheckNotes.setIsNotesUpdaterLaunched(true);
            while(ViewNotes.getIsshowNotesLaunched()){}
            String cookieIn,cookieOut;
            String[] values= new String[7];
            String html_notes="",html_cook_notes="";
            String identifiants;
            OutputStreamWriter out;
            if(isNetworkAvailable()){
                try{

                    // Couple Pseudo - Mot de passe
                    SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(parent);  // get User's Preferences
                    String mPseudo = sharedPref.getString(parent.getString(R.string.pref_pseudo_KEY), "John"); // Get the name of the promotion, to show it
                    String mMdp = sharedPref.getString(parent.getString(R.string.pref_mdp_KEY), "Doe"); // Get the name of the promotion, to show it
                    String mPseudoPrec  = sharedPref.getString("pref_pseudo_prec","");

                    if(!mPseudo.equals(mPseudoPrec))
                    {
                         newUser=true;
                         SharedPreferences.Editor editor = sharedPref.edit();
                         editor.putString("pref_pseudo_prec",mPseudo);
                         editor.apply();
                    }

                    if(!mPseudo.equals("John") && !mMdp.equals("Doe")){
                        identifiants = "password="+URLEncoder.encode(mMdp,"utf-8")+"&username="+URLEncoder.encode(mPseudo,"utf-8");


                        // ********** 1ere Etape ***********
                        // Connexion
                        URL url_login = new URL("https://campus.efrei.fr/campus/login/index.php");
                        HttpsURLConnection conn_login = (HttpsURLConnection) url_login.openConnection();
                        conn_login.setRequestMethod("POST");
                        conn_login.setDoOutput(true);
                        conn_login.setDoInput(true);
                        conn_login.setChunkedStreamingMode(0);
                        conn_login.setUseCaches(false);

                        // on envoie le couple Pseudo - Mot de passe
                        out = new OutputStreamWriter(conn_login.getOutputStream());
                        out.write(identifiants);
                        out.flush();

                            // on récupère les Cookies, et on parse le tout
                        cookieIn = getCookies(conn_login);
                        cookieOut = parseHeader(cookieIn,1);


                            // on se déconnecte
                        out.close();
                        conn_login.disconnect();







                            // ********** 2eme Etape ***********


                        // maintenant on se connecte à la page des notes pour choper la page pour avoir le cookie
                        URL url_cook_notes = new URL("http://campus.efrei.fr/campus/course/view.php?id=4");
                        HttpURLConnection conn_cook_notes = (HttpURLConnection) url_cook_notes.openConnection();
                        conn_cook_notes.setRequestProperty("Cookie",cookieOut);
                        conn_cook_notes.setChunkedStreamingMode(0);
                        conn_cook_notes.connect();

                        try{
                            InputStream is = new BufferedInputStream(conn_cook_notes.getInputStream());
                            html_cook_notes = streamToString(is);
                        }catch(Exception e){
                            Log.w("NotesUpdater","[3.1]"+e.toString());
                        }

                            // on se déconnecte
                        out.close();
                        conn_cook_notes.disconnect();

                        try{
                            //on cherche l'iframe pour récupérer l'adresse qui nous interresse
                            Matcher mat1 = Pattern.compile("<iframe\\s*src=\\\"(.*)\\\"\\s*style(.*)></iframe>", Pattern.MULTILINE|Pattern.DOTALL|Pattern.COMMENTS)
                                 .matcher(html_cook_notes);
                            mat1.find();
                            String url_int_notes_path = mat1.group(1);






                            // ********** 3eme Etape ***********

                            // Maintenant on choppe la page qui contient le cookie
                            URL url_int_notes = new URL(url_int_notes_path);

                            HttpURLConnection conn_int_notes = (HttpURLConnection) url_int_notes.openConnection();
                            conn_int_notes.setRequestProperty("Cache-Control", "max-age=0");
                            //conn_int_notes.setRequestProperty("Cookie",cookieOut);
                            conn_int_notes.setChunkedStreamingMode(0);
                            conn_int_notes.connect();


                            cookieIn = getCookies(conn_int_notes);
                            cookieOut = parseHeader(cookieIn,2);

                                // on se déconnecte
                            out.close();
                            conn_int_notes.disconnect();




                            // ********** 4eme Etape ***********

                            // Maintenant on choppe la page qui ne contient que les notes
                            URL url_notes = new URL("http://w4.efrei.fr/si/notes/elv/index.php?app=page");

                            HttpURLConnection conn_notes = (HttpURLConnection) url_notes.openConnection();
                            conn_notes.setRequestProperty("Cache-Control", "max-age=0");
                            conn_notes.setRequestProperty("Cookie",cookieOut);
                            conn_notes.setChunkedStreamingMode(0);
                            conn_notes.connect();

                            try{
                                InputStream is = new BufferedInputStream(conn_notes.getInputStream());
                                html_notes = streamToString(is);
                            }catch(Exception e){
                                Log.w("NotesUpdater","[4.1]"+e.toString());
                                ViewNotes.setIsUpdateError(4);
                            }

                            // on se déconnecte
                            out.close();
                            conn_notes.disconnect();

                            saveFiles(html_notes);
                        }
                        catch(Exception e){
                                Log.w("NotesUpdater","[1]"+e.toString());
                                ViewNotes.setIsUpdateError(1);
                        }
                    }
                    else{
                        ViewNotes.setIsUpdateError(21);
                    }
                    /*
                    else{
                        File fout = new File(parent.getFilesDir(),"notes_p1");
                        if(fout.exists()){
                                fout.delete();
                        }
                        fout = new File(parent.getFilesDir(),"notes_p2");
                        if(fout.exists()){
                                fout.delete();
                        }
                        fout = new File(parent.getFilesDir(),"notes_p3");
                        if(fout.exists()){
                            fout.delete();
                        }
                        ViewNotes.setIsUpdateError(12);
                    }*/
                }
                catch(Exception e){
                    Log.w("NotesUpdater","[5]"+e.toString());
                    ViewNotes.setIsUpdateError(5);
                }
            }
            else{ // si pas de réseau
                ViewNotes.setIsUpdateError(20);
            }
            setNextUpdate();
            ViewNotes.setIsNotesUpdaterLaunched(false);
            CheckNotes.setIsNotesUpdaterLaunched(false);
        }
        return null;
  }
    
    private String parseHeader(String header,int phase){
        String cookie="";
        
        if(phase==1){
            Matcher mat1 = Pattern.compile("MoodleSessioncampus=([0-9a-zA-Z]*);",Pattern.MULTILINE | Pattern.DOTALL|Pattern.COMMENTS).matcher(header);
            mat1.find();
            
            Matcher mat2 = Pattern.compile("MoodleSessionTestcampus=([0-9a-zA-Z]*);",Pattern.MULTILINE | Pattern.DOTALL|Pattern.COMMENTS).matcher(header);
            mat2.find();
            
            Matcher mat3 = Pattern.compile("(MOODLEID_campus=deleted;)(.*)(MOODLEID_campus=([0-9a-zA-Z%]*);)",Pattern.MULTILINE | Pattern.DOTALL).matcher(header);
            mat3.find();
            try{
                cookie = mat1.group(0);
                cookie += mat2.group(0);
                cookie += mat3.group(3);
            }catch(Exception e){
                Log.w("NoUp parseHeader","[5]"+e.toString());
            }
        }
        else if(phase==2){
            Matcher mat4 = Pattern.compile("EFREI_NOTES=([0-9a-zA-Z]*);",Pattern.MULTILINE | Pattern.DOTALL|Pattern.COMMENTS).matcher(header);
            mat4.find();
            try{
                cookie = mat4.group(0);
            }catch(Exception e){
                Log.w("NoUp parseHeader","[6]"+e.toString());
            }
        }
        
        
        return cookie;
    }
    
    private String streamToString(InputStream is) throws IOException{
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();
        String line = null;
        while ((line = reader.readLine()) != null) {
            sb.append(line).append("\n");
        }
        reader.close();
        is.close();
        return sb.toString();
    }
    
    private String getCookies(HttpURLConnection conn){
        String headerName=null;
        String cookie="";
        cookie = conn.getURL().getPath();
        for (int i=1; (headerName = conn.getHeaderFieldKey(i))!=null; i++) {
            if(headerName.equals("Set-Cookie")){
                cookie += conn.getHeaderField(i)+"\n";
            }
        }
        return cookie;
    }

    private boolean isNetworkAvailable(){
        boolean isAvailable;
        ConnectivityManager connectivityMgr =(ConnectivityManager) parent.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connectivityMgr.getActiveNetworkInfo();
        if(networkInfo!=null && networkInfo.isAvailable()){
            isAvailable = true;
        }
        else {
            isAvailable = false;
        }
        return isAvailable;
    }
    
    private void saveFiles(String in){
        
        
        int dernier_semestre=1;
        Matcher mat1=null;
        Matcher mat3 = Pattern.compile("&[a-z]{4,};",Pattern.MULTILINE | Pattern.DOTALL|Pattern.COMMENTS).matcher(in);
        in = mat3.replaceAll("");
        Matcher mat5 = Pattern.compile("</td>(\\W)+<tr>",Pattern.MULTILINE | Pattern.DOTALL|Pattern.COMMENTS).matcher(in);
        in = mat5.replaceAll("</td></tr><tr>");
        Matcher mat6 = Pattern.compile("<a\\s+href=\\\"[a-zA-Z0-9&_=?]+\\\"(.*)</a>",Pattern.MULTILINE | Pattern.DOTALL|Pattern.COMMENTS).matcher(in);
        in = mat6.replaceAll("");
        Matcher mat4 = Pattern.compile("<img\\s+src=\\\"img/[a-zA-Z]{2,10}\\.(:?gif|png|jpg)\\\"\\s+alt=\\\"[a-zA-Z]{0,10}\\\">",Pattern.MULTILINE | Pattern.DOTALL|Pattern.COMMENTS).matcher(in);
        in = mat4.replaceAll("");
        
        try{
            mat1 = Pattern.compile("<div\\s*id=\\\"releve1([0-9]{1,3})\\\"\\s*class=\\\"\\\">(.*)</div>(.*)</div>(.*)<div\\s*id=\\\"eleve12\\\"",Pattern.MULTILINE | Pattern.DOTALL|Pattern.COMMENTS).matcher(in);
            mat1.find();
            dernier_semestre = Integer.parseInt(mat1.group(1));
        }catch(Exception e){
            Log.w("NotesUpdater","dernier sem:"+dernier_semestre);
            ViewNotes.setIsUpdateError(13);
        }
        
        Matcher mat2 = Pattern.compile("<div\\s*id=\\\"bulletin11\\\"\\s*class=\\\"\\\">(.*)</div>(.*)</div>(.*)<div\\s*id=\\\"eleve13\\\"\\s*class=\\\"cacher\\\">(\\W){0,}<br/><br/>(.*)</div>(.*)</div>(.*)</div>(?:.*)</body>",Pattern.MULTILINE | Pattern.DOTALL|Pattern.COMMENTS).matcher(in);
        mat2.find();
        boolean isUpdateNeeded=true;
        FileOutputStream oS;
        File fout,fmd5_1,fmd5_2;
        try{
            // on utilise un fichier intermédiaire
            fmd5_1 = new File(parent.getFilesDir(),"notes_p1"+dernier_semestre+"_");
            if(fmd5_1.exists()){
                fmd5_1.delete();
            }
            
            // on y copie les données
            oS = parent.openFileOutput("notes_p1"+dernier_semestre+"_", Context.MODE_PRIVATE);
            oS.write(mat1.group(2).getBytes());
            oS.close();

            // on chope le contenu
            FileInputStream iS1 = new FileInputStream(fmd5_1);

            // on ouvre le fichier à comparer
            fmd5_2 = new File(parent.getFilesDir(),"notes_p1"+dernier_semestre); 

            if(fmd5_2.exists()){
                // on chope le contenu du fichier qui nous intéresse
                FileInputStream iS2 = new FileInputStream(fmd5_2);
                
                String s_f1 = streamToString(iS1);
                String s_f2 = streamToString(iS2);
                Log.v("NotesUpdater", "equal?"+s_f1.equals(s_f2));
                Log.v("NotesUpdater", "s_f1:"+s_f1.length()+" s_f2:"+s_f2.length());
                if(s_f1.equals(s_f2) && !newUser)
                {
                    isUpdateNeeded=false;
                }
            }
        }
        catch(Exception e){
            Log.w("NotesUpdater", "error 7:"+e.toString());
            ViewNotes.setIsUpdateError(7);
        }
        
        
        Log.v("NotesUpdater","AlertNeeded:"+isUpdateNeeded);
        CheckNotes.setIsAlertNeeded(isUpdateNeeded);
        ViewNotes.setIsUpdateNeeded(isUpdateNeeded);
        if(ViewNotes.getIsUpdateError()==0){
            ViewNotes.setNumPages(dernier_semestre);
            SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(parent);  // get User's Preferences
            SharedPreferences.Editor editor = sharedPref.edit();
            editor.putInt("nombre_semestres",dernier_semestre);
            editor.apply();
            Log.v("NotesUpdater","mNumPages "+dernier_semestre);
        }

        if(isUpdateNeeded)
        {
            for(int i=1;i<=dernier_semestre;i++){
                if(i<dernier_semestre){
                    mat1 = Pattern.compile("<div\\s*id=\\\"releve1"+i+"\\\"\\s*class=\\\"[a-z]{0,}\\\">(.*)</div>(.*)<div\\s*id=\\\"releve1"+(i+1)+"\\\"",Pattern.MULTILINE | Pattern.DOTALL|Pattern.COMMENTS).matcher(in);
                }
                else{
                    mat1 = Pattern.compile("<div\\s*id=\\\"releve1"+i+"\\\"\\s*class=\\\"\\\">(.*)</div>(.*)</div>(.*)<div\\s*id=\\\"eleve12\\\"",Pattern.MULTILINE | Pattern.DOTALL|Pattern.COMMENTS).matcher(in);
                }
                mat1.find();
                try{
                    fout = new File(parent.getFilesDir(),"notes_p1"+i);
                    if(fout.exists()){
                        fout.delete();
                    }
                    oS = parent.openFileOutput("notes_p1"+i, Context.MODE_PRIVATE);
                    oS.write(mat1.group(1).getBytes());
                    oS.close();


                }catch(Exception e){
                    Log.w("NotesUpdater", "error [8] "+i+" "+e.toString());
                    ViewNotes.setIsUpdateError(8);
                }
            }
            /*
            try{
                fout = new File(parent.getFilesDir(),"notes_p2");
                if(fout.exists()){
                    fout.delete();
                }
                oS = parent.openFileOutput("notes_p2", Context.MODE_PRIVATE);
                oS.write(mat2.group(5).getBytes());
                oS.close();
                
            }catch(Exception e){
                Log.w("NotesUpdater", "error [9]"+e.toString());
                ViewNotes.setIsUpdateError(9);
            }

            try{
                fout = new File(parent.getFilesDir(),"notes_p3");
                if(fout.exists()){
                    fout.delete();
                }
                oS = parent.openFileOutput("notes_p3", Context.MODE_PRIVATE);
                oS.write(mat2.group(2).getBytes());
                oS.close();
            }catch(Exception e){
                Log.w("NotesUpdater", "error [10]"+e.toString());
                ViewNotes.setIsUpdateError(10);
            }*/
        }
        
    }
    
    private void setNextUpdate(){
        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(parent);  // get User's Preferences
        SharedPreferences.Editor editor = sharedPref.edit();

        Boolean mNotif = sharedPref.getBoolean(parent.getString(R.string.pref_notif_KEY), false);
        
        if(mNotif)
        {
            int mNotifType = Integer.decode(sharedPref.getString(parent.getString(R.string.pref_value_notif_KEY), "2"));
            GregorianCalendar result;
            GregorianCalendar c= new GregorianCalendar();
            int year=c.get(c.YEAR);
            int month=c.get(c.MONTH);
            int day=c.get(c.DAY_OF_MONTH);
            int hour=c.get(c.HOUR_OF_DAY);
            long nextTime;

            
            switch(mNotifType){
                case 1:
                    if(hour<17 && hour>=5){
                        result = new GregorianCalendar(year,month,day,17,0);
                    }
                    else if(hour>=17){
                        result = new GregorianCalendar(year,month,day+1,5,0);
                    }
                    else{
                        result = new GregorianCalendar(year,month,day,5,0);
                    }
                    break;
                case 2:
                    result = new GregorianCalendar(year,month,day+1,5,0);
                    break;
                case 3:
                    result = new GregorianCalendar(year,month,day+2,5,0);
                    break;
                case 4:
                    result = new GregorianCalendar(year,month,day+7,5,0);
                    break;
                case 5:
                    result = new GregorianCalendar(year,month+1,day,5,0);
                    break;
                default:
                    result = new GregorianCalendar();
            }
            nextTime = result.getTimeInMillis();
            editor.putLong(parent.getString(R.string.pref_next_notif_KEY), nextTime);
            editor.apply();
 

            Intent resultIntent = new Intent(parent, CheckNotes.class);
            PendingIntent resultPendingIntent = PendingIntent.getService(parent, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            //long mNotifNext = sharedPref.getLong(parent.getString(R.string.pref_next_notif_KEY), 0);
            //Log.v("NotesUpdater", "mNotifNext:"+mNotifNext);

            AlarmManager alarmManager = (AlarmManager) parent.getSystemService(Context.ALARM_SERVICE);
            alarmManager.set(AlarmManager.RTC, nextTime, resultPendingIntent);
            //Log.v("NotesUpdater", "new Alarm defined");
        }
    }
}
